home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / vol11n07.zip / DOSCLIP.ASM < prev    next >
Assembly Source File  |  1992-03-17  |  69KB  |  1,973 lines

  1.             page    66,132
  2. ;============================================================================
  3. ; DOSCLIP.COM impliments a DOS clipboard
  4. ;
  5. ;       Usage: DOSCLIP [/B][/U]
  6. ;
  7. ;              B = Use Video BIOS calls
  8. ;              U = Uninstall
  9. ;
  10. ; Revision History: 
  11. ;
  12. ;       Version 1.0     Initial Release
  13. ;
  14. ;============================================================================
  15. POPTIME         equ     9                       ;Allow 1/2 second to popup
  16. COPYTIME        equ     180                     ;Allow 10 seconds to copy
  17.  
  18. STACKSIZE       equ     512                     ;TSR stack
  19. INSTDATASIZE    equ    offset DataBlockEnd - offset DataBlock
  20. MSGBOX_BUFFSIZE equ     1 * 132 * 2             ;Screen save buff for title
  21. HELPBOX_BUFFSIZE equ    5 * 132 * 2             ;Screen save buff for help
  22.  
  23. RES_STACK       equ     offset end_of_resident + STACKSIZE
  24. MSGBOX_BUFFER   equ     offset end_of_resident + STACKSIZE
  25. ATTR_BUFFER     equ     MSGBOX_BUFFER + MSGBOX_BUFFSIZE
  26.  
  27. ;----------------------------------------------------------------------------
  28. ; BIOS Data segment
  29. ;----------------------------------------------------------------------------
  30. bios_data       segment at 40h
  31.             org     17h
  32. shift_state     db      ?                       ;State of keyboard shift keys
  33.         org    1Ah
  34. keybuff_head    dw    ?            ;Start ptr for keyboard buff
  35. keybuff_tail    dw    ?             ;End ptr for keyboard buff
  36.  
  37.             org     4Eh
  38. video_buffoff   dw      ?                       ;Offset of video buffer
  39.             org     63h
  40. video_ioregs    dw      ?                       ;I/O addr of video controller
  41.         org    80h
  42. keybuff_start    dw    ?            ;Start ptr for keyboard buff
  43. keybuff_end    dw    ?             ;End ptr for keyboard buff
  44. video_rows      db      ?                       ;Number of rows on the screen
  45. bios_data       ends
  46.  
  47. ;----------------------------------------------------------------------------
  48. ; DOSCLIP Code and Data segments
  49. ;----------------------------------------------------------------------------
  50.             code    segment
  51.             assume  cs:code
  52.  
  53.             org     2ch
  54. env_segment     dw      ?                       ;Word containing the segment
  55.                                             ;  of the program's env. block.
  56.             org     80h
  57. command_tail    db      ?                       ;Offset of the command tail.
  58.  
  59.             org     100h
  60. prog:           jmp     initialize
  61. ;---------------------------------------------------------------------------            pushf
  62. ; Resident Data (Global to all sessions)
  63. ;---------------------------------------------------------------------------            pushf
  64. program         db      13,10
  65. program1    db    "DOSCLIP 1.0 "
  66. copyright       db      "(c) 1992 Douglas Boling"
  67. program2    db    10,13
  68.             db      "First published in PC Magazine, April 14, 1992"
  69.             db      13,10,"$",1Ah
  70.  
  71. def_marked_bw   db      70h                     ;Default marked attr B/W
  72. def_text_bw     db      70h                     ;Default text attr B/W
  73. bw_segment    dw    0B000h            ;Segment of B/W video memory
  74.  
  75. def_marked_clr  db      70h                     ;Default marked attr Color
  76. def_text_clr    db      71h                     ;Default text attr Color
  77. clr_segment    dw    0B800h            ;Segment of color video memory
  78.  
  79. attr_buffsize    dw    1024            ;Size of attribute buffer
  80. helpbox_buff      dw    0               ;Pointer to helpbox buffer
  81.  
  82. copykey        db    2eh            ;Hotkey for copy command 'C'
  83. copyshift    db    08h             ;Shift for copy hotkey. 'Alt'
  84. pastekey    db    2Fh            ;Hotkey for paste command 'V'
  85. pasteshift    db    08h             ;Shift for paste hotkey. 'Alt'
  86.  
  87. clipboard_buff    dd    0            ;Pointer to clipboard buffer
  88. clipboard_size    dw    4096            ;Max size of clipboard
  89. clipboard_dptr    dd    0            ;Ptr data in clipboard
  90. clipboard_dsize    dw    0            ;Size of data in clipboard
  91.  
  92. win_enhanced    db    0            ;Enhanced mode Windows active
  93.  
  94. indos_ptr       dd      -1                      ;Pointer to INDOS flag
  95. criterr_ptr     dd      -1                      ;Pointer to DOS crit err flag
  96.  
  97. int08h          dd      -1                      ;Int 08 vector (Timer)
  98. int09h          dd      -1                      ;Int 09 vector (Keyboard HW)
  99. int10h          dd      -1                      ;Int 10 vector (Video BIOS)
  100. int13h          dd      -1                      ;Int 13 vector (Disk BIOS)
  101. int16h          dd      -1                      ;Int 16 vector (Keyboard)
  102. int28h          dd      -1                      ;Int 28 vector (DOS Idle)
  103. int2Fh          dd      -1                      ;Int 2F vector (DOS Multiplex)
  104.  
  105. keycodes        db      3bh,51h,49h,4fh,47h,48h,50h,74h,73h,4bh,4dh
  106. keycodes_end    =       $
  107.  
  108. keyjmp_table    dw      offset cursor_rt        ;Index into key routines are
  109.         dw      offset cursor_lt        ;  inverse of order of
  110.             dw      offset cursor_clt       ;  keycode array.
  111.             dw      offset cursor_crt
  112.             dw      offset cursor_dn 
  113.             dw      offset cursor_up
  114.             dw      offset cursor_home    ;Home
  115.             dw      offset cursor_end    ;End
  116.             dw      offset cursor_top    ;Page Up
  117.             dw      offset cursor_bottom    ;Page Down
  118.             dw      offset showhelp        ;F1
  119.  
  120. helptag         db      "F1 for Help "
  121. helptag_end    =    $
  122.         db    0            ;Terminating 0 for helptag
  123.  
  124. no_help        db    0            ;Blocks help msg
  125. ;                        1234567891123456789212345678931234567894
  126. helpmsg1        db      " <Cursor> keys delete box/move cursor   "
  127.             db      " <Shift><Cursor> keys size box",0
  128. helpmsg2        db      " <Home>   Move to start of line         "
  129.             db      " <End>    Move to end of line",0
  130. helpmsg3        db      " <Pg Up>  Move to top of screen         "
  131.             db      " <Pg Dn>  Move to bot of screen",0
  132. helpmsg4        db      " <C>      Copy box into clipboard       "
  133.             db      " <P>      Paste clipboard data",0
  134. helpmsg5        db      " <Esc>    Exit the program",0
  135. ;
  136. ;Screen variables
  137. ;
  138. BIOSFlag    db    0            ;1 = Use Vid BIOS calls
  139. video_ptr    label    dword
  140. video_offset    dw    0            ;Offset of video memory
  141. video_seg    dw    0            ;Segment of video memory
  142. ;
  143. ;Switcher global data structures
  144. ;
  145. StartupInfo     =       $
  146.  sisVersion     dw      3                       ;Switcher structure ID
  147.  sisNextDev     dd      0                       ;Ptr to prev startup structure
  148.  sisVirtDevFile dd      0                       ;Ptr to name of opt dev drvr
  149.  sisReferenceData dd    0                       ;Data for Win dev drivr
  150.  sisInstData    dd      0                       ;Ptr to instance mem list
  151.  
  152. DataBlockPtr    dd      0                       ;Ptr to instance data
  153. DataBlockSize   dw      0                       ;Size of instance data
  154. StackBlockPtr   dd      0                       ;Ptr to instance stack
  155. StackBlockSize  dw      0                       ;Size of instance stack
  156.             dd      0                       ;Ptr to next block = 0 to
  157.             dw      0                       ;  terminate list
  158. ;============================================================================
  159. ;Instance data
  160. ;============================================================================
  161. DataBlock    =    $
  162. ;
  163. ; Program Instance data
  164. ;
  165. hotshift        db      0ah                     ;Shift condition for popup
  166. popflag         db      0                       ;Go active counter
  167.  
  168. int08_active    db      0                       ;Interrupt active flag
  169. int09_active    db      0                       ;Interrupt active flag
  170. int10_active    db      0                       ;Interrupt active flag
  171. int13_active    db      0                       ;Interrupt active flag
  172. int28_active    db      0                       ;Interrupt active flag
  173. int2F_active    db      0                       ;Interrupt active flag
  174. main_active     db      0                       ;TSR active flag
  175.  
  176. saved_ss        dw      0            ;Saved forground stack ptr
  177. saved_sp        dw      0
  178.  
  179. copy_flag    db    0            ;Flag indicating copy to clip
  180. paste_flag    db    0            ;Flag indicating paste 
  181.  
  182. marked_attr     db      0                       ;Screen attr for marked area
  183. text_attr       db      0                       ;Attribute for msg box text
  184.  
  185. cursor_pos      dw      0                       ;Cursor position at popup
  186. cursor_type     dw      0                       ;Cursor shape at popup
  187.  
  188. screen_page     db      0                       ;Active video page
  189. screen_size     label   word
  190. screen_cx       db      0                       ;Screen columns
  191. screen_cy       db      0                       ;Screen rows
  192.  
  193. marked_pos1     label   word
  194. marked_x1       db      0                       ;Marked area starting column
  195. marked_y1       db      0                       ;marked area starting row
  196. marked_pos2     label   word
  197. marked_x2       db      0                       ;Marked area ending column
  198. marked_y2       db      0                       ;marked area ending row
  199.  
  200. oldmarked_pos1  label   word
  201. oldmarked_x1    db      0                       ;Marked area starting row
  202. oldmarked_y1    db      0                       ;marked area starting column
  203. oldmarked_pos2  label   word
  204. oldmarked_x2    db      0                       ;Marked area columns
  205. oldmarked_y2    db      0                       ;marked area rows
  206.     
  207. boxactive       db      0                       ;Flag for message box
  208.  
  209. DataBlockEnd    =    $
  210.  
  211. ;============================================================================
  212. ; VIDEOINT processes BIOS video services interrupt (Int 10h)
  213. ;============================================================================
  214. videoint        proc    far
  215.             assume  cs:code,ds:nothing,es:nothing
  216.             inc     cs:int10_active
  217.             pushf
  218.             call    cs:[int10h]             ;Call old int
  219.             dec     cs:int10_active
  220.             iret                            ;Return
  221. videoint        endp
  222.  
  223. ;============================================================================
  224. ; DISKINT processes BIOS disk services interrupt (Int 13h)
  225. ;============================================================================
  226. diskint         proc    far
  227.             assume  cs:code,ds:nothing,es:nothing
  228.             inc     cs:int13_active
  229.             pushf
  230.             call    cs:[int13h]             ;Call old int
  231.             pushf
  232.             dec     cs:int13_active
  233.             popf
  234.             ret     2                       ;Return preserving flags
  235. diskint         endp
  236.  
  237. ;============================================================================
  238. ; TIMERINT processes timer interrupt (Int 08h)
  239. ;============================================================================
  240. timerint        proc    far
  241.             assume  cs:code,ds:nothing,es:nothing
  242.             pushf
  243.             call    cs:[int08h]             ;Call old int 8
  244.  
  245.         push    ax
  246.         push    ds
  247.         mov    ax,cs
  248.         mov    ds,ax
  249.         assume    ds:code
  250.     
  251.             cmp     int08_active,0          ;See if we are in this
  252.             jne     timerint_exit1          ;  routine already
  253.             inc     int08_active            ;Set int active flag
  254.  
  255.             cmp     popflag,0               ;See if we need to try to
  256.             jne     timer_check             ;  pop up
  257.  
  258.             cmp     paste_flag,1            ;See if there is data to
  259.         je      timer_paste_2           ;  paste from clipboard
  260.         ja      timer_paste
  261. timerint_exit:
  262.             dec     int08_active            ;Clear int active flag
  263. timerint_exit1:
  264.         pop    ds
  265.         pop    ax
  266.             iret                            ;Return
  267. timer_check:
  268.             call    check_system            ;See if system OK to pop up
  269.             or      ax,ax
  270.             jne     timerint_dec
  271.             call    main                    ;Call the TSR
  272.             mov     popflag,1
  273. timerint_dec:
  274.             dec     popflag
  275.         jmp     short timerint_exit
  276. timer_paste_2:
  277.             cmp     paste_flag,1            ;See if there is data to
  278.         jne    timerint_exit        ;  paste
  279.             call    push_key
  280.         jnc    timer_paste_2
  281.             jmp     short timerint_exit
  282. timer_paste:
  283.         cmp    win_enhanced,0        ;See if Win/386 active
  284.         je    timer_paste_1
  285.  
  286.         call    getwinclip        ;Get data from the clipboard
  287.         cmp    ax,-1            ;If -1, can't open clipboard,
  288.         je    timerint_exit        ;  try again later.
  289.         mov    paste_flag,0         ;If 0, no data available.
  290.         or     ax,ax
  291.         je    timerint_exit
  292.         mov    clipboard_dsize,ax        ;Else, AX = bytes
  293.         mov    ax,word ptr clipboard_buff    ;  read from CB.
  294.         mov    word ptr clipboard_dptr,ax
  295.         mov    paste_flag,1
  296.         jmp    short timer_paste_2
  297. timer_paste_1:
  298.         mov    paste_flag,0        ;If no Win/386, see if any
  299.         cmp    clipboard_dsize,0    ;  data in the clipboard.
  300.         je    timerint_exit        ;  If not, cancel paste.
  301.         mov    paste_flag,1
  302.         jmp    short timer_paste_2
  303. timerint        endp
  304.  
  305. ;============================================================================
  306. ; KEYINT processes keyboard interrupts (Int 09h)
  307. ;============================================================================
  308. keyint          proc    far
  309.             assume  cs:code,ds:nothing,es:nothing
  310.             push    ax
  311.             push    ds
  312.             mov     ax,40h
  313.             mov     ds,ax                   ;Set ES to bios data segment
  314.             assume  ds:bios_data
  315.             mov     ah,ds:[shift_state]
  316.             and     ah,0fh                  ;Mask lock bits
  317.             cmp     ah,cs:[copyshift]
  318.             je      keyint_copy
  319. keyint_1:
  320.             cmp     ah,cs:[pasteshift]
  321.             je      keyint_paste
  322. keyint_jmp:
  323.             pop     ds
  324.             pop     ax
  325.             jmp    cs:[int09h]             ;Call old int 9
  326. keyint_exit:
  327.                 cli                             ;Disable interrupts
  328.                 in      al,61h                  ;Reset the keyboard
  329.                 mov     ah,al                   ;  controller
  330.                 or      al,80h
  331.                 out     61h,al
  332.                 mov     al,ah
  333.                 out     61h,al
  334.  
  335.                 mov     al,20h                  ;Signal end-of-interrupt to
  336.                 out     20h,al                  ;  the interrupt controller
  337.                 sti                             ;Enable interrupts
  338.             pop     ds
  339.             pop     ax
  340.         iret
  341. keyint_copy:
  342.         in    al,60h            ;Get scan code from keyboard
  343.         cmp    al,cs:copykey
  344.         jne    keyint_1
  345.         mov     cs:popflag,POPTIME      ;Set timer to pop up
  346.             jmp     short keyint_exit
  347. keyint_paste:
  348.         in    al,60h            ;Get scan code from keyboard
  349.         cmp    al,cs:pastekey        ;Compare to paste hotkey
  350.         jne    keyint_jmp
  351.         mov    cs:paste_flag,2        ;Set Paste flag
  352.             jmp     short keyint_exit
  353. keyint          endp
  354.  
  355. ;============================================================================
  356. ; IDLEINT processes DOS Idle interrupt (Int 28h)
  357. ;============================================================================
  358. idleint         proc    far
  359.             assume  cs:code,ds:nothing,es:nothing
  360.             pushf
  361.             call    cs:[int28h]             ;Call old int
  362.  
  363.         push    ds
  364.         push    cs
  365.         pop    ds
  366.         assume    ds:code
  367.             cmp     int28_active,0          ;See if we are in this
  368.             jne     idleint_exit1           ;  routine already
  369.             inc     int28_active            ;Set int active flag
  370.             cmp     popflag,0               ;See if we need to try to
  371.             jne     idle_check              ;  pop up
  372. idleint_exit:
  373.             dec     int28_active            ;Clear int active flag
  374. idleint_exit1:
  375.         pop    ds
  376.             iret                            ;Return
  377. idle_check:
  378.             push    ax
  379.             call    check_system            ;See if OK to pop up.  Ignore
  380.             or      al,al                   ;  INDOS since in idle.
  381.             jne     idleint_1
  382.             mov     popflag,0               ;Clear popup flag
  383.             call    main                    ;Call the TSR
  384. idleint_1:
  385.             pop     ax
  386.             jmp     short idleint_exit
  387. idleint         endp
  388.  
  389. ;============================================================================
  390. ; MUXINT processes DOS multiplex interrupt (Int 2Fh)
  391. ;============================================================================
  392. muxint          proc    far
  393.             assume  cs:code,ds:nothing,es:nothing
  394.  
  395.         cmp    ax,1605h        ;See if Windows launch
  396.         je    mux_winstart
  397.         cmp    ax,1606h        ;See if Windows terminate
  398.         je    mux_winend
  399.         cmp    ax,1608h        ;See if Windows launch
  400.         je    mux_wingo         ;  complete
  401.  
  402.         cmp     ax,4b05h                ;See if switcher get instance
  403.             je      init_instance           ;  data.
  404. muxint_jmp:
  405.             jmp     cs:[int2Fh]             ;Jump to old int
  406. mux_winend:
  407.             test    dx,01h                  ;See if enhanced mode Windows
  408.             jne     muxint_jmp
  409.         dec    cs:win_enhanced        ;Clear Enhanced mode win flag
  410.             jmp     short muxint_jmp
  411. mux_wingo:
  412.         cmp    cs:clipboard_dsize,0    ;If Windows starts and we
  413.         je    muxint_jmp        ;  have data in our 
  414.         cmp    cs:win_enhanced,0    ;  clipboard, copy our
  415.         je    muxint_jmp        ;  data to the Win clipboard
  416.         mov    cs:copy_flag,COPYTIME
  417.         jmp    short muxint_jmp
  418. mux_winstart:
  419.             test    dx,01h                  ;See if enhanced mode Windows
  420.             jne     init_instance
  421.             inc     cs:win_enhanced
  422. init_instance:
  423.             pushf
  424.             call    cs:[int2fh]             ;Call old int
  425.             mov     word ptr cs:[sisNextDev],bx
  426.             mov     word ptr cs:[sisNextDev+2],es
  427.             push    cs                      ;ES:BX point to switcher struc
  428.             pop     es
  429.             mov     bx,offset StartupInfo
  430.             jmp     short muxint_exit
  431. muxint_exit:
  432.             iret
  433. muxint        endp
  434.  
  435. ;---------------------------------------------------------------------------            pushf
  436. ; Check System Determines if the system is in a state compatible with TSRs
  437. ; Exit: AL - ORed flags for DOS Idle OK
  438. ;       AH - State of INDOS flag
  439. ;---------------------------------------------------------------------------            pushf
  440. check_system    proc    near
  441.             assume  cs:code,ds:code,es:nothing
  442.             push    bx
  443.             push    ds
  444.             xor     ax,ax
  445.             or      al,int10_active         ;Check BIOS video int
  446.             or      al,int13_active         ;Check BIOS disk int
  447.             lds     bx,criterr_ptr          ;Check DOS critical error
  448.             or      al,byte ptr ds:[bx]     ;  flag.
  449.             lds     bx,cs:indos_ptr         ;Check INDOS flag
  450.             mov     ah,byte ptr ds:[bx]
  451. check_sys_exit:
  452.             pop     ds
  453.             pop     bx
  454.             ret
  455. check_system    endp
  456.  
  457. ;-----------------------------------------------------------------------------
  458. ; GETWINCLIP  Gets any data from the Windows Clipboard
  459. ; Exit AX - FF Can't open clipboard
  460. ;           0  Error in clipboard or clipboard data not available
  461. ;           Else, number of bytes read from clipboard
  462. ;-----------------------------------------------------------------------------
  463. getwinclip    proc    near
  464.         assume    ds:code
  465.         mov    ax,1701h        ;Open Clipboard
  466.         int    2fh
  467.         or    ax,ax            ;Error opening, exit
  468.         mov    ax,-1
  469.         je    getwinclip_exit1
  470.         push    bx
  471.         push    dx
  472.         push    es
  473.         mov    ax,1704h        ;Get clipboard data size
  474.         mov    dx,7            ;Request OEM Text
  475.         int    2fh
  476.         or    dx,dx            ;See if too much data
  477.         jne    getwinclip_exit
  478.         cmp    ax,clipboard_size
  479.         jbe    getwinclip_1
  480.         xor    ax,ax            ;Indicate error
  481.         jmp    short getwinclip_exit
  482. getwinclip_1:
  483.         cmp    dx,ax                 ;If 0 size, no data in 
  484.         je    getwinclip_exit        ;  correct format.
  485.         push    ax
  486.         mov    ax,1705h        ;Get clipboard data
  487.         les    bx,clipboard_buff
  488.         mov    dx,7            ;Get OEM text
  489.         int    2fh
  490.         or    ax,ax
  491.         pop    ax
  492.         je    getwinclip_exit        
  493.         dec    ax
  494. getwinclip_exit:
  495.         push    ax
  496.         mov    ax,1708h        ;Close Clipboard
  497.         int    2fh
  498.         pop    ax
  499.         pop    es
  500.         pop    dx
  501.         pop    bx
  502. getwinclip_exit1:
  503.         ret
  504. getwinclip    endp
  505.  
  506. ;-----------------------------------------------------------------------------
  507. ; GETCLIPSIZE  Gets the size of the data in the Windows clipboard
  508. ;-----------------------------------------------------------------------------
  509. getclipsize    proc    near
  510.         assume    ds:code
  511.         mov    ax,1701h        ;Open Clipboard
  512.         int    2fh
  513.         or    ax,ax            ;Error opening, exit
  514.         je    getclipsize_exit
  515.         mov    ax,1704h        ;Get clipboard data size
  516.         mov    dx,7            ;Request OEM Text
  517.         int    2fh
  518.         mov    ax,1708h        ;Close Clipboard
  519.         int    2fh
  520.         pop    es
  521.         pop    dx
  522.         pop    bx
  523. getclipsize_exit:
  524.         ret
  525. getclipsize    endp
  526.  
  527. ;-----------------------------------------------------------------------------
  528. ; SETWINCLIP  Sets the Windows clipboard
  529. ; Exit:  ZF - Set if error
  530. ;-----------------------------------------------------------------------------
  531. setwinclip    proc    near
  532.         assume    ds:code
  533.         push    bx
  534.         push    cx
  535.         push    dx
  536.         push    si
  537.         push    es
  538.         mov    ax,1700h        ;Check API
  539.         int    2fh
  540.         or    ax,ax            ;no API
  541.         je    setwinclip_exit1
  542.         mov    ax,1701h        ;Open Clipboard
  543.         int    2fh
  544.         or    ax,ax            ;Error opening, exit
  545.         je    setwinclip_exit1
  546.         mov    ax,1702h        ;Clear Clipboard
  547.         int    2fh
  548.         or    ax,ax            ;Error, exit
  549.         je    setwinclip_exit1
  550.         mov    ax,1703h        ;Set clipboard data
  551.         les    bx,clipboard_buff    ;ES:BX ptr to data
  552.         xor    si,si            ;SI,CX = data size
  553.         mov    cx,clipboard_dsize
  554.         mov    dx,7            ;Data format is OEM text
  555.         int    2fh
  556. setwinclip_exit:
  557.         mov    ax,1708h        ;Close Clipboard
  558.         int    2fh
  559.         or    ax,ax            ;Set ZF if error
  560. setwinclip_exit1:
  561.         pop    es
  562.         pop    si
  563.         pop    dx
  564.         pop    cx
  565.         pop    bx
  566.         ret
  567. setwinclip    endp
  568.  
  569. ;-----------------------------------------------------------------------------
  570. ; INCKEYPTR Incriments the keyboard buffer pointer
  571. ; Entry: DI - Current Keyboard tail pointer
  572. ;-----------------------------------------------------------------------------
  573. inckeyptr    proc    near
  574.         assume    ds:bios_data
  575.         inc    di            ;Make room in buffer
  576.         inc    di
  577.         cmp    di,ds:[keybuff_end]    ;Get ptr to end of buffer
  578.         jne    inckeyptr_1
  579.         mov    di,ds:[keybuff_start]    ;Get ptr to buffer offset
  580. inckeyptr_1:
  581.         ret
  582. inckeyptr    endp
  583.  
  584. ;-----------------------------------------------------------------------------
  585. ; PUSH KEY  Fills the keyboard buffer with data from the clipboard.
  586. ; Exit: CF - Set if keyboard buffer full
  587. ;       AX - modified
  588. ;-----------------------------------------------------------------------------
  589. push_key    proc    near
  590.         assume    ds:nothing,es:nothing
  591.         push    di
  592.         push    si
  593.         push    ds
  594.         push    es
  595.         cli
  596.         mov    ax,bios_data
  597.         mov    ds,ax
  598.         assume    ds:bios_data
  599.         cli                ;No interrupts
  600.         mov    di,ds:[keybuff_tail]
  601.         push    di
  602.         call     inckeyptr
  603.         cmp    di,ds:[keybuff_head]    ;See if buffer full
  604.         pop    di
  605.         stc
  606.         je    push_key_exit
  607.         
  608.         les    si,cs:[clipboard_dptr]    ;Get ptr to clip data
  609.         mov    ax,word ptr cs:[clipboard_buff]    
  610.         add    ax,cs:[clipboard_dsize] ;Add size of data
  611.         cmp    ax,si            ;See if at end of buffer
  612.         mov    al,es:[si]        ;Get clipboard byte
  613.         jne    push_key_2        ;No, continue
  614.         mov    cs:[paste_flag],0        ;Clear paste flag
  615.         mov    si,word ptr cs:[clipboard_buff]    ;Reset data ptr
  616.         dec    si
  617. push_key_2:
  618.         or    al,al            ;Don't stuff null char
  619.         je    push_key_3
  620.         cmp    al,0ah            ;Don't stuff line feeds
  621.         je    push_key_3
  622.           xor    ah,ah            ;Clear scan code
  623.         cmp    al,0dh            ;If CR character, add proper
  624.         jne    push_key_21        ;  scan code for Word Perfect
  625.         mov    ah,1ch
  626. push_key_21:        
  627.         mov    ds:[di],ax        ;Push data into keyboard buff
  628.         call    inckeyptr
  629.         mov    ds:[keybuff_tail],di    ;Save keybuff ptr
  630. push_key_3:
  631.         inc    si            ;Update clip data ptr
  632.         mov    word ptr cs:[clipboard_dptr],si    ;Save clipdata ptr
  633.         clc
  634. push_key_exit:
  635.         sti                ;Allow interrupts
  636.         pop    es
  637.         pop    ds
  638.         pop    si
  639.         pop    di
  640.         ret
  641. push_key    endp
  642.  
  643. ;============================================================================
  644. ; MAIN  This routine does most of the work for the TSR
  645. ;============================================================================
  646. main            proc    near
  647.             assume  cs:code,ds:code,es:nothing
  648.             cmp     main_active,0           ;See if already active
  649.             jne     main_exit
  650.             cli
  651.             inc     main_active
  652.             mov     [saved_sp],sp           ;Save old stack pointer
  653.             mov     [saved_ss],ss
  654.  
  655.             mov     ax,cs                   ;Set ss:sp to internal stack
  656.             mov     ss,ax
  657.             mov     sp,RES_STACK
  658.             sti                ;Enable interrupts
  659.             cld                ;Set string direction UP
  660.  
  661.             push    bx
  662.             push    cx
  663.             push    dx
  664.             push    di
  665.             push    si
  666.             push    bp
  667.             push    es
  668.     
  669.             mov     ah,0fh                  ;Get display mode
  670.             int     10h
  671.             cmp     al,7
  672.             je      main_1                  ;Pop up only if in text mode.
  673.             cmp     al,4
  674.             jb      main_1
  675. main_exit1:
  676.             pop     es
  677.             pop     bp
  678.             pop     si
  679.             pop     di
  680.             pop     dx
  681.             pop     cx
  682.             pop     bx
  683.     
  684.             cli
  685.             mov     ss,[saved_ss]           ;Restore old stack
  686.             mov     sp,[saved_sp]
  687.             dec     main_active
  688. main_exit:
  689.             ret
  690. main_1:
  691.         xor    dl,dl
  692.         mov    no_help,dl        ;Enable help message
  693.         mov    copy_flag,dl        ;Clear copy to clip flag
  694.             cmp     ah,80
  695.             jb      main_exit1
  696.             mov     screen_page,bh          ;Save active video page
  697.             mov     screen_cx,ah            ;Save screen columns
  698.  
  699.             mov     ah,3                    ;Get cursor position
  700.             int     10h
  701.             mov     cursor_pos,dx           ;Save cursor information
  702.             mov     cursor_type,cx
  703.         cmp    dh,0            ;If on top line, move down 1
  704.         jne    main_11            ;  to miss banner.
  705.         inc    dh
  706. main_11:
  707.         mov    marked_pos1,dx        ;Save initial cursor position
  708.             mov     ax,40h
  709.             mov     es,ax                   ;Set ES to bios data segment
  710.             assume  es:bios_data
  711.             mov     ah,12h                  ;Determine if CGA by checking
  712.             mov     bl,10h                  ;  for EGA compatibility
  713.             int     10h
  714.             mov     al,24                   ;CGA, only 25 rows on screen
  715.             cmp     bl,10h
  716.             je      main_2
  717.  
  718.             mov     al,es:video_rows        ;Get number of rows on screen
  719. main_2:
  720.             mov     screen_cy,al        ;Save screen rows
  721.         mov    ax,es:video_buffoff    ;Copy ptr to video memory
  722.         mov    video_offset,ax
  723.  
  724.             mov     ax,marked_pos1        ;Copy starting pos to ending
  725.             mov     marked_pos2,ax        ;  pos to zero block.
  726.             mov     oldmarked_pos1,ax
  727.             mov     oldmarked_pos2,ax
  728.     
  729.             test    es:video_ioregs,40h     ;See if color or monochrome
  730.             jne     main_colorvid
  731.  
  732.         mov    si,offset def_marked_bw    ;Point to B/W parameters
  733.             jmp     short main_3
  734. main_colorvid:
  735.         mov    si,offset def_marked_clr ;Point to color parameters    
  736. main_3:
  737.             push    ds
  738.             pop     es
  739.             assume  es:code
  740.  
  741.         mov    di,offset marked_attr    ;Copy default attributes 
  742.         movsw
  743.         lodsw                ;Get Video buffer segment
  744.         mov    video_seg,ax
  745.  
  746.             mov     ah,1            ;Hide the cursor by changing
  747.             mov     cx,200h                 ;  the size of the cursor
  748.             int     10h
  749.  
  750.         call    init_attrlist        ;Initialize attr save list
  751.         jc    main_end1
  752.  
  753.             mov     dx,marked_pos1          ;Mark initial cursor where
  754.             call    getchar                 ;  the old cursor was
  755.             mov     ah,marked_attr        ;Mark cursor position on
  756.             call    putchar            ;  screen.
  757. main_loop:
  758.             cmp     boxactive,1             ;If box active, don't reprint
  759.             je      main_4                  ;  the box.
  760.  
  761.         mov    al,marked_y2        ;If cursor on top line, don't
  762.         or    al,marked_y2        ;  print the title box.
  763.         je    main_4
  764.             call    msgbox                  ;Draw title box
  765. main_4:
  766.         call    getkey            ;Wait for a key
  767.             cmp     al,27                   ;If ESC, end.
  768.             je      main_end
  769.             cmp     ah,pastekey             ;If 'v' paste and exit
  770.             je      main_paste
  771.             cmp     ah,28                   ;If Enter, copy and exit
  772.             je      main_copy
  773.             cmp     ah,copykey              ;If 'c' copy and exit
  774.             je      main_copy 
  775.             mov     al,ah            ;Copy scan code
  776. main_6:
  777.             mov     di,offset keycodes
  778.             mov     cx,offset keycodes_end - offset keycodes
  779.             repne   scasb
  780.             jne     main_loop
  781.             shl     cx,1            ;Convert key num into jump
  782.             mov     bx,cx            ;  table index.
  783.         mov    ax,marked_pos2        ;Preload parameters into regs
  784.         mov    cx,screen_size        ;  to save code
  785.             call    [keyjmp_table+bx]    ;Call key routine
  786.             jmp     short main_loop
  787. main_copy:
  788.         mov    copy_flag,1
  789.         jmp    short main_end
  790. main_paste:
  791.         cmp    win_enhanced,0        ;If enhanced mode Windows 
  792.         je    main_paste_1        ;  active, get clipboard
  793.         call    getwinclip        ;  data from the Windows
  794.         jmp    short main_end        ;  Clipboard.
  795. main_paste_1:
  796.         cmp    clipboard_dsize,0    ;If clipboard empty, don't
  797.         je    main_end        ;  paste.
  798.         mov    paste_flag,1
  799. main_end:
  800.             call    clearmarked             ;Restore attributes
  801.             call    clearbox                ;Delete title box
  802. main_end1:
  803.             mov     ah,1                    ;Set cursor type
  804.             mov     cx,cursor_type
  805.             mov     bh,screen_page
  806.             int     10h
  807.             mov     ah,2                    ;Set cursor position
  808.             mov     dx,cursor_pos
  809.             int     10h
  810.             jmp     main_exit1
  811. main            endp
  812.  
  813. ;-----------------------------------------------------------------------------
  814. ; CURSOR KEYS Handles the actions of the cursor keys as the user uses them
  815. ;             to mark the selected area.
  816. ; Entry: AL - marked_x2
  817. ;        AH - marked_y2
  818. ;        CL - screen_cx
  819. ;        CH - screen_cy
  820. ;-----------------------------------------------------------------------------
  821. cursor_keys     proc    near
  822. ; CURSOR HOME  Moves the cursor to the left most column
  823. cursor_home:
  824.             xor     al,al            ;Zero current column
  825.             jmp     short cursor_1
  826. ; CURSOR END  Moves the cursor to the right most column
  827. cursor_end:
  828.             mov     al,cl            ;Set Cur column to screen cols
  829.             dec     al
  830.             jmp     short cursor_1
  831. ; CURSOR TOP  Moves the cursor to the top row
  832. cursor_top:
  833.             mov     ah,1                    ;Move to line 1 to avoid
  834.             jmp     short cursor_1          ;  title erase
  835. ; CURSOR END  Moves the cursor to the bottom row
  836. cursor_bottom:
  837.             mov     ah,ch            ;Set Cur Row to screen rows
  838.             jmp     short cursor_1
  839. ; CURSOR UP  Moves the marked orgin up one row
  840. cursor_up:
  841.             or      ah,ah
  842.             je      cursor_1
  843.             dec     ah
  844.             jmp     short cursor_1
  845. ; CURSOR DN  Moves the marked orgin down one row
  846. cursor_dn:
  847.             cmp     ah,ch
  848.             je      cursor_1
  849.             inc     ah
  850.             jmp     short cursor_1
  851. ; CURSOR CLT  Moves the marked orgin left 8 columns
  852. cursor_clt:
  853.         sub    al,8
  854.         jae    cursor_1
  855.             xor     al,al
  856.             jmp     short cursor_1
  857. ; CURSOR CRT  Moves the marked orgin right 8 columns
  858. cursor_crt:
  859.         add    al,8
  860.         dec    cl
  861.         cmp    al,cl
  862.         jb    cursor_1
  863.             mov     al,cl
  864.             jmp     short cursor_1
  865. ; CURSOR LT  Moves the marked orgin left one col
  866. cursor_lt:
  867.             or      al,al
  868.             je      cursor_1
  869.             dec     al
  870.             jmp     short cursor_1
  871. ; CURSOR RT  Moves the marked orgin right one col
  872. cursor_rt:
  873.         dec    cl
  874.             cmp     al,cl
  875.             jae     cursor_1
  876.             inc     al
  877. cursor_1:
  878.         mov    marked_pos2,ax        ;Save new position
  879.         push    ax
  880.             mov     ah,2                    ;Get shift state
  881.             int     16h
  882.             and     al,3
  883.         pop    ax
  884.             jne     cursor_2
  885.             mov     marked_pos1,ax          ;Not shifted, set points equal
  886. cursor_2:
  887.             or      ah,ah                   ;If cursor on top line, clear
  888.             jne     cursor_3                ;  title box so user can see
  889.             call    clearbox                ;  what is on top line.
  890. cursor_3:
  891.             call    drawmarked
  892.             ret
  893. cursor_keys     endp
  894.  
  895. ;-----------------------------------------------------------------------------
  896. ; DRAWMARKED  Displays the marked area by changing the screen attributes
  897. ;             inside the marked area.
  898. ;-----------------------------------------------------------------------------
  899. drawmarked      proc    near
  900.             push    es
  901.  
  902.             mov     ax,marked_pos1
  903.             mov     dx,marked_pos2
  904.             cmp     dx,oldmarked_pos2
  905.             jne     drawmarked_1
  906.  
  907.             cmp     ax,oldmarked_pos1
  908.             je      drawmarked_exit
  909. drawmarked_1:
  910.             mov     bx,offset marked_pos1
  911.             mov     cx,4
  912. drawmarked_2:
  913.             call    find_min                ;AX = upper left corner
  914.             call    find_max                ;DX = lower right corner
  915.             add     bx,2
  916.             loop    drawmarked_2
  917. drawmarked_7:
  918.             sub     dx,ax                   ;Compute size of area
  919.  
  920.             xor     cx,cx
  921.             mov     cl,dl                   ;Copy column count
  922.             mov     si,cx
  923.             inc     si
  924.             mov     cl,dh                   ;Copy row count
  925.             inc     cx
  926.             mov     dx,ax                   ;Copy starting row, column
  927. drawmarked_8:
  928.             push    cx                      ;Save row count
  929.             push    dx                      ;Save cursor position
  930.             mov     cx,si                   ;Get column count
  931. drawmarked_9:
  932.             mov     bx,offset marked_pos1
  933.             call    chk_inwin
  934.             mov     ah,al                   ;Save in marked area flag
  935.     
  936.             mov     bx,offset oldmarked_pos1
  937.             call    chk_inwin
  938.  
  939.             cmp     ah,al                   ;See if in or out of both
  940.             je      drawmarked_11           ;  areas. If so, no change.
  941.  
  942.             push    ax                      ;Save in-window flags
  943.             call    getchar
  944.             pop     bx
  945.             or      bh,bh                   ;See if in marked area
  946.             je      drawmarked_10
  947.  
  948.             mov     ah,marked_attr        ;Mark character
  949.             call    putchar
  950.  
  951.             jmp     short drawmarked_11
  952. drawmarked_10:
  953.         call    get_attr        ;Get saved screen attribute
  954.             call    putchar            ;Restore attribute
  955. drawmarked_11:
  956.             inc     dl
  957.             loop    drawmarked_9
  958.  
  959.             pop     dx
  960.             pop     cx
  961.             inc     dh
  962.             loop    drawmarked_8
  963.  
  964.             mov     ax,marked_pos1          ;Update old pointers
  965.             mov     oldmarked_pos1,ax
  966.             mov     ax,marked_pos2
  967.             mov     oldmarked_pos2,ax
  968. drawmarked_exit:
  969.             pop     es
  970.             ret
  971. drawmarked      endp
  972.  
  973. ;-----------------------------------------------------------------------------
  974. ; CLEARMARKED  Restores the marked area to its original screen attributes
  975. ;-----------------------------------------------------------------------------
  976. clearmarked     proc    near
  977.             assume  ds:code
  978.         push    es
  979.             mov     bx,offset marked_pos1
  980.             call    compute_box
  981.             sub     ax,dx
  982.             xor     cx,cx
  983.             mov     cl,al
  984.             mov     si,cx                   ;Save column count
  985.             inc     si
  986.             mov     cl,ah
  987.             inc     cx
  988.         xor    bx,bx
  989.         cmp    copy_flag,0
  990.         je    clearmarked_3
  991.         mov    bx,clipboard_size
  992.         les    di,clipboard_buff
  993.         mov    word ptr [clipboard_dptr],di
  994. clearmarked_3:
  995.             push    cx
  996.             push    dx
  997.             mov     cx,si            ;Get row count
  998. clearmarked_4:
  999.             call    getchar
  1000.         or    bx,bx            ;If copying data to 
  1001.         je    clearmarked_5        ;  clipboard, save char.
  1002.         stosb
  1003.         dec    bx
  1004. clearmarked_5:
  1005.         call    get_attr        ;Get saved screen attribute
  1006.             call    putchar
  1007.             inc     dl
  1008.             loop    clearmarked_4
  1009.         or    bx,bx
  1010.         je    clearmarked_6
  1011.         mov    ax,0a0dh        ;Append CR-LF to line
  1012.         stosw
  1013.         dec    bx
  1014.         dec    bx
  1015. clearmarked_6:
  1016.             pop     dx
  1017.             pop     cx
  1018.             inc     dh
  1019.             loop    clearmarked_3
  1020.         cmp    copy_flag,0
  1021.         je    clearmarked_exit
  1022.         xor    al,al
  1023.         stosb
  1024.         dec    bx
  1025.         sub    bx,clipboard_size
  1026.         not    bx
  1027.         mov    clipboard_dsize,bx
  1028.         mov    ax,word ptr cs:[clipboard_buff]
  1029.         mov    word ptr cs:[clipboard_dptr],ax
  1030.         cmp    win_enhanced,0        ;If enhanced mode Windows
  1031.         je    clearmarked_exit    ;  active, save data to 
  1032.         call    setwinclip        ;  Windows clipboard
  1033. clearmarked_exit:
  1034.         pop    es
  1035.             ret
  1036. clearmarked     endp
  1037.  
  1038. ;-----------------------------------------------------------------------------
  1039. ; GET ATTR  Gets a saved attribute in the attribute buffer for a given 
  1040. ;           cursor location.
  1041. ; Entry:  DX - Row, Column of character
  1042. ; Exit:   AH - Attribute
  1043. ;-----------------------------------------------------------------------------
  1044. get_attr    proc    near
  1045.         push    cx
  1046.         push    dx
  1047.         push    si
  1048.         push    ax
  1049.         call    compute_offset        ;Get count into buffer
  1050.         mov    si,ATTR_BUFFER
  1051.         xor    ax,ax
  1052.         mov    dx,ax
  1053. get_attr_1:
  1054.         lodsb                ;Get count byte
  1055.         inc    si
  1056.         or    al,al
  1057.         je    get_attr_exit
  1058.         sub    cx,ax
  1059.         jae    get_attr_1
  1060.         mov    dh,[si-1]        ;Get attribute
  1061. get_attr_exit:
  1062.         pop    ax
  1063.         mov    ah,dh            ;Copy attribute
  1064.         pop    si
  1065.         pop    dx
  1066.         pop    cx
  1067.         ret
  1068. get_attr    endp
  1069.  
  1070. ;-----------------------------------------------------------------------------
  1071. ; INIT ATTRLIST  Initializes the attribute list
  1072. ;-----------------------------------------------------------------------------
  1073. init_attrlist    proc    near
  1074.             assume  ds:code
  1075.         mov    bx,screen_size        ;Get size of screen
  1076.         inc    bh
  1077.         inc    bh
  1078.         xor    ax,ax
  1079.         mov    dx,ax            ;Start at top left corner
  1080.         mov    cx,ax
  1081.         xchg    bh,cl            ;CX-Col count, BX-Row cnt
  1082.         mov    si,bx
  1083.         mov    di,ATTR_BUFFER        ;Get pointer to buffer
  1084.         call    getchar
  1085.         mov    bh,ah
  1086.         mov    bl,0
  1087. init_attrlist_1:
  1088.         push    cx
  1089.         push    dx
  1090.         mov    cx,si            ;Get number of columns
  1091. init_attrlist_2:
  1092.         call    getchar         ;Read attribute
  1093.         cmp    bh,ah            ;Compare attributes
  1094.         jne    init_attrlist_newblk    ;If different write block
  1095.         inc    bl            ;Incriment count
  1096.         cmp    bl,-1            ;If count full, write block
  1097.         je    init_attrlist_newblk
  1098.         mov    bh,ah            ;Copy attribute value
  1099. init_attrlist_3:
  1100.         inc    dl            ;Next column
  1101.         loop    init_attrlist_2
  1102.         pop    dx
  1103.         pop    cx
  1104.         inc    dh            ;Next row
  1105.         loop    init_attrlist_1
  1106.         clc
  1107. init_attrlist_exit:
  1108.             ret
  1109. init_attrlist_newblk:
  1110.         mov    ds:[di],bx        ;Write old block to list
  1111.         inc    di            ;Update ptr
  1112.         inc    di
  1113.         mov    bl,1            ;New count
  1114.         mov    bh,ah            ;Copy new attribute 
  1115.         cmp    di,helpbox_buff
  1116.         jb    init_attrlist_3        ;If list runs into the help
  1117.         inc    no_help            ;  buffer, disable help
  1118.         push    ax
  1119.         mov    ax,helpbox_buff        ;If past helpbox buffer, exit
  1120.         add    ax,HELPBOX_BUFFSIZE
  1121.         cmp    di,ax
  1122.         pop    ax
  1123.         jb    init_attrlist_3        ;If list past help box
  1124.         stc                        ;  buffer, exit prog.
  1125.         jmp    short init_attrlist_exit
  1126. init_attrlist    endp
  1127.  
  1128. ;-----------------------------------------------------------------------------
  1129. ; COMPUTE OFFSET  Computes the offset into the attribute buffer for a
  1130. ;                 given cursor location.
  1131. ; Entry:  DX - Row, Column of character
  1132. ; Exit:   CX - Offset in buffer.
  1133. ;-----------------------------------------------------------------------------
  1134. compute_offset  proc    near
  1135.             push    ax
  1136.         push    dx
  1137.             mov     al,dh                   ;Copy column
  1138.             mul     screen_cx               ;Mul by width of screen
  1139.             xor     dh,dh
  1140.             add     ax,dx                   ;Add row
  1141.         xchg    cx,ax
  1142.         pop    dx
  1143.             pop     ax
  1144.             ret
  1145. compute_offset  endp
  1146.  
  1147. ;-----------------------------------------------------------------------------
  1148. ; CHK INWIN  Determines if a character is inside the bounds of an area
  1149. ; Entry:  BX - Pointer to bounding rectangle
  1150. ;           x1  db  point 1 column
  1151. ;           y1  db  point 1 row
  1152. ;           x2  db  point 2 column
  1153. ;           y2  db  point 2 row
  1154. ;         DX - Row, Column of character
  1155. ; Exit:   AL - <> 0 if inside area
  1156. ;-----------------------------------------------------------------------------
  1157. chk_inwin       proc    near
  1158.             push    bx
  1159.             push    cx
  1160.  
  1161.             push    ax                      ;Save AX
  1162.             push    dx                      ;Save current cursor pos
  1163.             call    compute_box             ;DX = UL corner, AX = LR corner
  1164.             pop     bx
  1165.             xchg    bx,dx                   ;DX = cur cursor, BX=UL corner
  1166.             mov     cx,ax                   ;CX = LR corner
  1167.             pop     ax                      ;Restore AX
  1168.  
  1169.             mov     al,0                    ;Clear inbox flag
  1170.  
  1171.             cmp     dl,bl                   ;See if above starting row
  1172.             jb      chk_inwin_exit
  1173.             cmp     dh,bh                   ;See if left of starting col
  1174.             jb      chk_inwin_exit
  1175.  
  1176.             cmp     dl,cl                   ;See if below ending row
  1177.             ja      chk_inwin_exit
  1178.             cmp     dh,ch                   ;See if right of ending col
  1179.             ja      chk_inwin_exit
  1180.             inc     al
  1181. chk_inwin_exit:
  1182.             pop     cx
  1183.             pop     bx
  1184.             ret
  1185. chk_inwin       endp
  1186.  
  1187. ;-----------------------------------------------------------------------------
  1188. ; FIND MIN  Computes the smaller of two screen coordinates.
  1189. ; Entry:  AX - Row, Column of 1st coordinate
  1190. ;         BX - Pointer to 2nd coordinate
  1191. ; Exit:   AX - Result coordinate.
  1192. ;-----------------------------------------------------------------------------
  1193. find_min        proc    near
  1194.             cmp     al,[bx]
  1195.             jbe     find_min_1
  1196.             mov     al,[bx]
  1197. find_min_1:
  1198.             cmp     ah,[bx+1]
  1199.             jbe     find_min_2
  1200.             mov     ah,[bx+1]
  1201. find_min_2:
  1202.             ret
  1203. find_min        endp
  1204.  
  1205. ;-----------------------------------------------------------------------------
  1206. ; FIND MAX  Computes the larger of two screen coordinates.
  1207. ; Entry:  DX - Row, Column of 1st coordinate
  1208. ;         BX - Pointer to 2nd coordinate
  1209. ; Exit:   AX - Result coordinate.
  1210. ;-----------------------------------------------------------------------------
  1211. find_max        proc    near
  1212.             cmp     dl,[bx]
  1213.             jae     find_max_1
  1214.             mov     dl,[bx]
  1215. find_max_1:
  1216.             cmp     dh,[bx+1]
  1217.             jae     find_max_2
  1218.             mov     dh,[bx+1]
  1219. find_max_2:
  1220.             ret
  1221. find_max        endp
  1222.  
  1223. ;-----------------------------------------------------------------------------
  1224. ; COMPUTE BOX  Puts the starting row/column in DX and the SI and CX
  1225. ; Entry:  BX - Pointer to coordinates
  1226. ; Exit:   AX - Ending row/column
  1227. ;         DX - Starting row/column
  1228. ;-----------------------------------------------------------------------------
  1229. compute_box     proc    near
  1230.             mov     ax,[bx]
  1231.             mov     dx,[bx+2]
  1232.  
  1233.             cmp     al,dl
  1234.             ja      compute_box_1
  1235.             xchg    al,dl
  1236. compute_box_1:
  1237.             cmp     ah,dh
  1238.             ja      compute_box_2
  1239.             xchg    ah,dh
  1240. compute_box_2:
  1241.             ret
  1242. compute_box     endp
  1243.  
  1244. ;-----------------------------------------------------------------------------
  1245. ; SHOWHELP  Displays a help screen on the first three lines of the display
  1246. ;-----------------------------------------------------------------------------
  1247. showhelp        proc    near
  1248.         cmp    byte ptr no_help,0    ;See if help msg disabled.
  1249.         jne    showhelp_exit
  1250.             mov     dh,1                    ;Box at top of screen
  1251.             mov     cx,5
  1252.             mov     di,helpbox_buff
  1253. showhelp_1:
  1254.             push    cx
  1255.             call    saveline
  1256.             inc     dh
  1257.             pop     cx
  1258.             loop    showhelp_1
  1259.  
  1260.             mov     dh,1
  1261.             mov     si,offset helpmsg1      ;Write help text line
  1262.             call    writeline
  1263.             inc     dh                      ;Move to next line
  1264.             mov     si,offset helpmsg2
  1265.             call    writeline
  1266.             inc     dh                      ;Move to next line
  1267.             mov     si,offset helpmsg3
  1268.             call    writeline
  1269.             inc     dh                      ;Move to next line
  1270.             mov     si,offset helpmsg4
  1271.             call    writeline
  1272.             inc     dh                      ;Move to next line
  1273.             mov     si,offset helpmsg5
  1274.             call    writeline
  1275.  
  1276.         call    getkey            ;Wait for a key
  1277.             mov     dh,1                    ;Box at top of screen
  1278.             mov     cx,5
  1279.             mov     si,helpbox_buff
  1280. showhelp_2:
  1281.             push    cx
  1282.             call    restoreline
  1283.             inc     dh
  1284.             pop     cx
  1285.             loop    showhelp_2
  1286. showhelp_exit:
  1287.             ret
  1288. showhelp        endp
  1289.  
  1290. ;-----------------------------------------------------------------------------
  1291. ; MSGBOX  displays a message in a text window on the top line of the
  1292. ;         screen.  The current data on the screen is saved.
  1293. ;-----------------------------------------------------------------------------
  1294. msgbox          proc    near
  1295.             mov     dh,0                    ;Box at top of screen
  1296.         mov    al,boxactive
  1297.             cmp     al,2                 ;Display sum only
  1298.             je      msgbox_1
  1299.             or      al,al                  ;If box already displayed,
  1300.             jne     msgbox_1                ;  don't save screen data.
  1301.             mov     di,MSGBOX_BUFFER
  1302.             call    saveline
  1303. msgbox_1:
  1304.         mov    si,offset program1
  1305.         mov    cx,offset program2 - offset program1
  1306.         xor    dx,dx
  1307. msgbox_11:
  1308.         lodsb
  1309.         call    writechar
  1310.         loop    msgbox_11
  1311.         xor    cx,cx
  1312.         mov    cl,screen_cx
  1313.         sub    cl,offset helptag_end - offset helptag
  1314.         ja    msgbox_2
  1315.         mov    cl,screen_cx
  1316.         inc    ch
  1317. msgbox_2:
  1318.         push    dx
  1319. msgbox_3:
  1320.             mov     al,' '                  ;Pad line with spaces
  1321.             call    writechar
  1322.             cmp     dl,cl
  1323.             jb      msgbox_3
  1324.         or    ch,ch
  1325.         jne    msgbox_5
  1326. msgbox_4:
  1327.         mov    si,offset helptag
  1328.         call    writestr
  1329. msgbox_5:
  1330.         pop    dx
  1331.             mov     boxactive,1             ;Set box active flag
  1332.             ret
  1333. msgbox          endp
  1334.  
  1335. ;-----------------------------------------------------------------------------
  1336. ; CLEARBOX  removes the title box from the screen.
  1337. ;-----------------------------------------------------------------------------
  1338. clearbox        proc    near
  1339.             cmp     boxactive,0             ;If box already displayed,
  1340.             je      clearbox_2              ;  don't save screen data.
  1341.             mov     si,MSGBOX_BUFFER
  1342.             mov     dh,0                    ;Box at top of screen
  1343.             call    restoreline
  1344.             mov     boxactive,0             ;Clear box displayed flag
  1345. clearbox_2:
  1346.             ret
  1347. clearbox        endp
  1348.  
  1349. ;-----------------------------------------------------------------------------
  1350. ; WRITELINE  Writes a line of help text to the screen.  The line is padded
  1351. ;            with spaces to the right.
  1352. ; Entry: DH - Line on screen to write
  1353. ;        SI - Pointer to ASCIIZ text
  1354. ;-----------------------------------------------------------------------------
  1355. writeline       proc    near
  1356.             push    dx
  1357.             xor     dl,dl                   ;Start at left side of screen
  1358.             call    writestr                ;Write string
  1359. writeline_2:
  1360.             mov     al,' '                  ;Pad line with spaces
  1361.             call    writechar
  1362.             cmp     dl,screen_cx
  1363.             jb      writeline_2
  1364.             pop     dx
  1365.             ret
  1366. writeline       endp
  1367.  
  1368. ;-----------------------------------------------------------------------------
  1369. ; SAVELINE  Saves the contents of a screen line ot a buffer
  1370. ; Entry: DH - Line on screen to save
  1371. ;        DI - Pointer to save buffer
  1372. ;-----------------------------------------------------------------------------
  1373. saveline        proc    near
  1374.             push    dx
  1375.             xor     dl,dl                   ;Start at left side of screen
  1376.             xor     cx,cx
  1377.             mov     cl,screen_cx
  1378. saveline_1:
  1379.             call    getchar                 ;Read character from screen
  1380.             stosw
  1381.             inc     dl                      ;Point to next character
  1382.             loop    saveline_1
  1383.             pop     dx
  1384.             ret
  1385. saveline        endp
  1386.  
  1387. ;-----------------------------------------------------------------------------
  1388. ; RESTORELINE  Restores the screen that was covered by a line of program
  1389. ;              helptext.
  1390. ; Entry: DH - Line on screen to restore
  1391. ;        SI - Pointer to buffer that contains original screen contents
  1392. ;-----------------------------------------------------------------------------
  1393. restoreline     proc    near
  1394.             push    dx
  1395.             xor     dl,dl                   ;Start at left side of screen
  1396.             xor     cx,cx
  1397.             mov     cl,screen_cx
  1398. restoreline_1:
  1399.             lodsw
  1400.             call    writechar1              ;Read character from screen
  1401.             loop    restoreline_1
  1402.             pop     dx
  1403.             ret
  1404. restoreline     endp
  1405.  
  1406. ;-----------------------------------------------------------------------------
  1407. ; WRITESTR  Writes a string to the screen.
  1408. ; Entry: DH,DL - Row/Column to write the string
  1409. ;        SI - Pointer to ASCIIZ text
  1410. ;-----------------------------------------------------------------------------
  1411. writestr        proc    near
  1412.             mov     ah,text_attr            
  1413. writestr1:
  1414.             lodsb                           ;Read text from string, then
  1415.             or      al,al                   ;  call putchar to write to
  1416.             je      writestr_1        ;  the screen.
  1417.             call    writechar1
  1418.             jmp     short writestr1
  1419. writestr_1:
  1420.             ret
  1421. writestr        endp
  1422.  
  1423. ;-----------------------------------------------------------------------------
  1424. ; WRITECHAR  Writes a character to the screen
  1425. ; Entry: AL - Character
  1426. ;        DX - Row, Column 
  1427. ;-----------------------------------------------------------------------------
  1428. writechar       proc    near
  1429.             mov     ah,text_attr
  1430. writechar1:
  1431.             call    putchar
  1432.             inc     dl
  1433.             ret
  1434. writechar       endp
  1435.  
  1436. ;-----------------------------------------------------------------------------
  1437. ; GETCHAR  Reads a character and its attribute from the screen
  1438. ; Entry:  DH - Row of character to read
  1439. ;         DL - Column of character to read
  1440. ; Exit:   AL - Character
  1441. ;         AH - Attribute
  1442. ;-----------------------------------------------------------------------------
  1443. getchar         proc    near
  1444.             push    bx
  1445.         cmp    BIOSFlag,0
  1446.         jne    getchar_bios
  1447.         push    cx
  1448.         push    si
  1449.         push    ds
  1450.         call    compute_offset        ;Get offset into buffer
  1451.         shl    cx,1            ;Double for char and attr
  1452.         lds    si,video_ptr        ;Get ptr to video memory
  1453.         add    si,cx            ;Double since char and attr
  1454.         lodsw                ;Read char/attribute
  1455.         pop    ds
  1456.         pop    si
  1457.         pop    cx
  1458.         jmp    short getchar_exit
  1459. getchar_bios:
  1460.             mov     ah,2                    ;Set cursor
  1461.             mov     bh,screen_page
  1462.             int     10h
  1463.             mov     ah,8                    ;Read character/attr
  1464.             int     10h
  1465. getchar_exit:
  1466.             pop     bx
  1467.             ret
  1468. getchar         endp
  1469.  
  1470. ;-----------------------------------------------------------------------------
  1471. ; PUTCHAR  Writes a character and its attribute to the screen
  1472. ; Entry:  AL - Character to write
  1473. ;         AH - Attribute to write
  1474. ;         DH - Row of character to write
  1475. ;         DL - Column of character to write
  1476. ;-----------------------------------------------------------------------------
  1477. putchar         proc    near
  1478.             push    bx
  1479.             push    cx
  1480.             push    ax
  1481.         cmp    BIOSFlag,0
  1482.         jne    putchar_bios
  1483.         push    di
  1484.         push    es
  1485.         call    compute_offset        ;Get offset into buffer
  1486.         shl    cx,1             ;Double since char and attr
  1487.         les    di,video_ptr
  1488.         add    di,cx                  ;Add to start of buffer
  1489.         stosw                ;Read char/attribute
  1490.         pop    es
  1491.         pop    di
  1492.         jmp    short putchar_exit
  1493. putchar_bios:
  1494.             mov     ah,2                    ;Set cursor
  1495.             mov     bh,screen_page
  1496.             int     10h
  1497.             pop     ax
  1498.         push    ax
  1499.             mov     bl,ah                   ;Copy attribute
  1500.             mov     ah,9                    ;Read character/attr
  1501.             mov     cx,1
  1502.             int     10h
  1503. putchar_exit:
  1504.         pop    ax
  1505.             pop     cx
  1506.             pop     bx
  1507.             ret
  1508. putchar         endp
  1509.  
  1510. ;-----------------------------------------------------------------------------
  1511. ; GETKEY  Waits for a key from the keyboard.
  1512. ; Exit:   AX - Scan code, ASCII char from keyboard.
  1513. ;-----------------------------------------------------------------------------
  1514. getkey          proc    near
  1515.             mov     ah,1                    ;Check for key
  1516.             int     16h
  1517.             jnz     getkey_exit
  1518.             int     28h                     ;Call DOS Idle
  1519.         mov    ax,1680h        ;Release Timeslice
  1520.         int    2fh
  1521.             jmp     short getkey
  1522. getkey_exit:
  1523.             xor     ax,ax                   ;Get key
  1524.             int     16h
  1525.         ret
  1526. getkey          endp
  1527.         align    16
  1528. end_of_resident =       $
  1529.  
  1530. ;----------------------------------------------------------------------------
  1531. ; Non-resident data.
  1532. ;----------------------------------------------------------------------------
  1533. alrdy_installed db      0                       ;Installed flag
  1534. installed_seg   dw      0                       ;Segment of installed code
  1535. dos_version     dw      0                       ;DOS version
  1536.  
  1537. infomsg2        db      "DOSCLIP uninstalled$"
  1538.  
  1539. errmsg0         db      "Need DOS 3.0 or greater$"
  1540. errmsg1         db      "DOSCLIP not installed$"
  1541. errmsg2         db      "Usage: DOSCLIP [/B][/U]",13,10
  1542.             db      "/B = Use Video BIOS",13,10
  1543.             db      "/U = Uninstall",13,10,"$"
  1544. errmsg3         db      "Can",39,"t uninstall$"
  1545. errmsg4         db      "DOSCLIP already installed$"
  1546. errmsg5         db      "Can not find Critical error flag$"
  1547. endmsg          db      13,10,"$"
  1548.  
  1549. infomsg1        db      "DOSCLIP installed",13,10,10
  1550.             db      "Copy key is "
  1551.         db    "Alt  C",13,10
  1552.             db      "Paste key is "
  1553.         db    "Alt  V","$"
  1554.  
  1555. ;----------------------------------------------------------------------------
  1556. ; Initialization routine.
  1557. ;----------------------------------------------------------------------------
  1558. initialize      proc    near
  1559.             assume  cs:code,ds:code,es:code
  1560.             cld
  1561.             mov     dx,offset program       ;Print copyright message
  1562.             call    printmsgcr
  1563.  
  1564.             mov     ah,30h                  ;Get DOS version
  1565.             int     21h
  1566.             xchg    al,ah                   ;Swap major, minor numbers
  1567.             mov     dx,offset errmsg0       ;Bad DOS version
  1568.             cmp     ah,3                    ;Run if DOS 3.0 or greater.
  1569.             jb      disp_error
  1570.             mov     dos_version,ax          ;Save version number
  1571.  
  1572.             mov     ax,offset end_of_code+512       ;Set stack ptr
  1573.             mov     sp,ax
  1574.             add     ax,15
  1575.             mov     cl,4                    ;Convert offset to segment size
  1576.             shr     ax,cl
  1577.             mov     ah,4ah                  ;Reduce memory allocation
  1578.             int     21h
  1579.  
  1580.             call    find_installed        ;See if already installed
  1581.             jc      init_1
  1582.             inc     alrdy_installed        ;Yes, set flag
  1583.             mov     installed_seg,es        ;Save seg of installed code
  1584. init_1:
  1585.             push    ds
  1586.             pop     es
  1587.             mov     dx,offset errmsg4       ;Default message
  1588.             mov     di,80h            ;Parse command line
  1589.             xor     cx,cx
  1590.             or      cl,[di]                 ;Get length of cmd line
  1591.             je      init_exit
  1592. init_2:
  1593.             mov     al,'/'
  1594.             repne   scasb                   ;Find command line switches
  1595.             jne     init_exit
  1596.             mov     al,[di]                 ;Get comamnd line switch
  1597.             or      al,20h
  1598.             cmp     al,'b'                  ;See if Video BIOS parameter
  1599.             jne     init_3
  1600.             inc    BIOSFlag
  1601.             jmp     short init_2
  1602. init_3:
  1603.             cmp     al,'u'                  ;See if uninstall
  1604.             je    init_4
  1605.             mov     dx,offset errmsg2       ;Print useage statement
  1606. ;
  1607. ;Display error message.
  1608. ;
  1609.             assume  ds:nothing
  1610. disp_error:
  1611.             push    cs
  1612.             pop     ds
  1613.             assume  ds:code
  1614.             call    printmsgcr              ;print string
  1615.  
  1616.             mov     ax,4c01h                ;Terminate with RC = 1
  1617.             int     21h
  1618. init_4:
  1619.             call    remove                  ;Remove installed copy
  1620.             jc    disp_error
  1621.         jmp    short exit
  1622. init_exit:
  1623.             cmp     alrdy_installed,0
  1624.             jne     disp_error
  1625.             call    install
  1626.             jc      disp_error
  1627. exit:
  1628.             mov     ax,4C00h                ;Terminate with RC = 0
  1629.             int     21h
  1630. initialize      endp
  1631.  
  1632. ;-----------------------------------------------------------------------------
  1633. ; INSTALL Installs the program
  1634. ;-----------------------------------------------------------------------------
  1635.             assume  cs:code,ds:code,es:code
  1636. install         proc    near
  1637.             mov     ah,34h                  ;Get ptr to INDOS flag
  1638.             int     21h
  1639.             mov     word ptr indos_ptr,bx
  1640.             mov     word ptr indos_ptr[2],es
  1641.             call    findCEF                 ;Get ptr to crit error flag
  1642.             jnc     install_1
  1643.             jmp     install_error
  1644. install_1:
  1645. ;
  1646. ;Set interrupt vectors
  1647. ;
  1648.             mov     word ptr criterr_ptr,bx
  1649.             mov     word ptr criterr_ptr[2],es
  1650.             mov     al,08h                  ;Get/set the timer interrupt
  1651.             mov     dx,offset timerint
  1652.             mov     di,offset int08h
  1653.             call    set_interrupt
  1654.             mov     al,09h                  ;Get/set the keyboard int
  1655.             mov     dx,offset keyint
  1656.             mov     di,offset int09h
  1657.             call    set_interrupt
  1658.             mov     al,10h                  ;Get/set the video interrupt
  1659.             mov     dx,offset videoint
  1660.             mov     di,offset int10h
  1661.             call    set_interrupt
  1662.             mov     al,13h                  ;Get/set the disk interrupt
  1663.             mov     dx,offset diskint
  1664.             mov     di,offset int13h
  1665.             call    set_interrupt
  1666.             mov     al,28h                  ;Get/set the DOS idle int
  1667.             mov     dx,offset idleint
  1668.             mov     di,offset int28h
  1669.             call    set_interrupt
  1670.             mov     al,2Fh                  ;Get/set the DOS Multiplex
  1671.             mov     dx,offset muxint
  1672.             mov     di,offset int2Fh
  1673.             call    set_interrupt
  1674.  
  1675.         push    cs
  1676.         push    cs
  1677.         pop    ds
  1678.         assume    ds:code
  1679.         pop    es
  1680.         assume    es:code
  1681.             mov     dx,offset infomsg1      ;Print program installed msg
  1682.             call    printmsgcr
  1683. ;
  1684. ;Init buffer pointers.
  1685. ;
  1686.         mov    dx,ATTR_BUFFER        ;Set pointers for resident
  1687.         add    dx,attr_buffsize    ;  code.
  1688.         mov    helpbox_buff,dx
  1689.         add    dx,HELPBOX_BUFFSIZE
  1690. ;
  1691. ;Init clipboard pointers.
  1692. ;
  1693.         mov    word ptr [clipboard_buff],dx 
  1694.         mov    bx,dx            ;Save size of save data area
  1695.         add    dx,clipboard_size    ;Add size of clipboard
  1696.         mov    ax,cs
  1697.          mov    word ptr [clipboard_buff+2],ax
  1698.          mov    word ptr [clipboard_dptr+2],ax
  1699.          mov    word ptr [clipboard_dsize],0
  1700.          mov    paste_flag,0
  1701. ;
  1702. ;Init switcher structures
  1703. ;
  1704.             mov     word ptr [DataBlockPtr+2],ax
  1705.             mov     word ptr [DataBlockPtr],offset DataBlock
  1706.             mov     word ptr [DataBlockSize],INSTDATASIZE
  1707.  
  1708.             mov     word ptr [StackBlockPtr+2],ax
  1709.             mov     word ptr [StackBlockPtr],offset end_of_resident
  1710.         sub    bx,offset end_of_resident    ;Compute size of
  1711.             mov     word ptr [StackBlockSize],bx    ;  Data save area
  1712.  
  1713.             mov     word ptr [sisInstData+2],ax
  1714.             mov     ax,offset DataBlockPtr     
  1715.             mov     word ptr [sisInstData],ax
  1716.         push    dx            ;Save Ptr to end of resident
  1717.         
  1718.             mov     ax,1600h                ;See if Enhanced mode windows
  1719.             int     2fh
  1720.             or      al,al
  1721.             je      nowin
  1722.             inc     win_enhanced            ;Set enhanced mode flag
  1723. nowin:
  1724.         pop     dx            ;Get Ptr to end of resident
  1725.             add     dx,15
  1726.             mov     cl,4
  1727.             shr     dx,cl
  1728.             mov     ax,3100h                ;Terminate and stay resident
  1729.             int     21h
  1730. install_error:
  1731.             ret
  1732. install         endp
  1733.  
  1734. ;-----------------------------------------------------------------------------
  1735. ; REMOVE uninstalls the installed program from memory.
  1736. ;-----------------------------------------------------------------------------
  1737. remove          proc    near
  1738.             assume  ds:code,es:code
  1739.             push    ds
  1740.             push    es
  1741.  
  1742.             mov     ds,installed_seg        ;Point DS to installed code
  1743.             assume  ds:nothing
  1744.  
  1745.             mov     dx,offset errmsg1       ;Not installed message
  1746.             cmp     alrdy_installed,0
  1747.             je      remove_error1
  1748.  
  1749.             mov     al,8                    ;Restore int 8 (Timer)
  1750.             mov     dx,offset timerint
  1751.             mov     di,offset int08h
  1752.             call    restore_int
  1753.             jc      remove_error
  1754.             mov     al,9                    ;Restore int 9 (keyboard)
  1755.             mov     dx,offset keyint
  1756.             mov     di,offset int09h
  1757.             call    restore_int
  1758.             jc      remove_error
  1759.             mov     al,10h                  ;Restore int 10h (BIOS Video)
  1760.             mov     dx,offset videoint
  1761.             mov     di,offset int10h
  1762.             call    restore_int
  1763.             jc      remove_error
  1764.             mov     al,13h                  ;Restore int 13h (BIOS disk)
  1765.             mov     dx,offset diskint
  1766.             mov     di,offset int13h
  1767.             call    restore_int
  1768.             jc      remove_error
  1769.             mov     al,28h                  ;Restore int 28h (DOS Idle)
  1770.             mov     dx,offset idleint
  1771.             mov     di,offset int28h
  1772.             call    restore_int
  1773.             jc      remove_error
  1774.             mov     al,2Fh                  ;Restore int 2Fh (DOS Mux)
  1775.             mov     dx,offset muxint
  1776.             mov     di,offset int2Fh
  1777.             call    restore_int
  1778.             jc      remove_error
  1779.             mov     es,ds:[2ch]             ;Get installed env seg
  1780.             mov     ah,49h
  1781.             int     21h                     ;Free installed env segment
  1782.             push    ds
  1783.             pop     es
  1784.             mov     ah,49h                  ;Free installed program segment
  1785.             int     21h
  1786.             mov     ax,cs
  1787.             mov     ds,ax
  1788.             mov     es,ax
  1789.             mov     dx,offset infomsg2      ;Print program removed msg
  1790.             call    printmsgcr
  1791.             clc
  1792. remove_exit:
  1793.             pop     ds
  1794.             pop     es
  1795.             ret
  1796. remove_error:
  1797.             mov     dx,offset errmsg3       ;Can't uninstall msg
  1798. remove_error1:
  1799.             stc
  1800.             jmp     short remove_exit
  1801. remove          endp
  1802.  
  1803. ;-----------------------------------------------------------------------------
  1804. ; SETINTERRUPT Get and sets an interrupt
  1805. ; Entry: AL - Interrupt number
  1806. ;        DX - Pointer to new interrupt routine
  1807. ;        DI - Pointer to storage location for old interrupt vector
  1808. ;-----------------------------------------------------------------------------
  1809.             assume  cs:code,ds:code,es:nothing
  1810. set_interrupt   proc    near
  1811.             push    es
  1812.             push    ax
  1813.             mov     ah,35h                  ;DOS get interrupt
  1814.             int     21h
  1815.             pop     ax
  1816.             mov     word ptr [di],bx        ;Save old vector
  1817.             mov     word ptr [di+2],es
  1818.             mov     ah,25h                  ;DOS set interrupt
  1819.             int     21h
  1820.             pop     es
  1821.             ret
  1822. set_interrupt   endp
  1823.  
  1824. ;-----------------------------------------------------------------------------
  1825. ; RESTOREINT Checks to see if an interrupt vector has been changed, if not
  1826. ;            the interrupt vector is restored with its original value
  1827. ; Entry:    AL - Interrupt number
  1828. ;        DS:DX - Pointer to current interrupt routine
  1829. ;        DS:DI - Pointer to old interrupt vector
  1830. ;-----------------------------------------------------------------------------
  1831.             assume  cs:code,ds:nothing
  1832. restore_int     proc    near
  1833.             push    es
  1834.             push    ax
  1835.             mov     ah,35h                  ;DOS get interrupt
  1836.             int     21h
  1837.             pop     ax                      ;Get back interrupt number
  1838.             cmp     dx,bx                   ;Compare routine offset
  1839.             jne     restoreint_error
  1840.             mov     bx,es                   ;Get current vector segment
  1841.             mov     cx,ds                   ;Get installed segment
  1842.             cmp     cx,bx                   ;Compare routine segment
  1843.             jne     restoreint_error
  1844.             push    ds
  1845.             lds     dx,ds:[di]              ;Get old vector
  1846.             mov     ah,25h                  ;DOS set interrupt
  1847.             int     21h
  1848.             clc
  1849.             pop     ds
  1850. restoreint_exit:
  1851.             pop     es
  1852.             ret
  1853. restoreint_error:
  1854.             stc
  1855.             jmp     short restoreint_exit
  1856. restore_int     endp
  1857.  
  1858. ;-----------------------------------------------------------------------------
  1859. ; FINDCEF  Finds the DOS ErrorMode (Critical error) flag
  1860. ; Exit:   ES:BX - Segment,offset of ErrorMode flag
  1861. ;         CF - Clear if flag found
  1862. ;-----------------------------------------------------------------------------
  1863. findCEF         proc    near
  1864.         mov    ah,34h            ;Get InDOS address
  1865.         int    21h
  1866.         dec    bx        
  1867.         cmp    dos_version,30ah    ;If DOS 3.1 or later, ErrorMode
  1868.         jnc    findCEF_exit        ;  sits before InDOS.
  1869.  
  1870.             mov     ax,3e80h                ;CMP opcode
  1871.         mov     si,028cdh               ;Int 28 Opcode
  1872.         mov     dl,75h                  ;JNE Opcode
  1873.             mov     cx,-1                   ;max search length
  1874.             mov     di,bx                   ;start at INDOS address
  1875. findCEF_1:
  1876.         repne   scasb                   ;do the search
  1877.             jcxz    findCEF_notfound        ;branch if search failed
  1878.         cmp     es:[di],ah              ;Check other half of CMP opcode
  1879.         jne     findCEF_1
  1880.         cmp     byte ptr es:[di+4],dl   ;Check for JNE
  1881.         jne     findCEF_1
  1882.         cmp     word ptr es:[di+6],si   ; Check for Int 28h call
  1883.         jne     findCEF_1               ;Resume loop if not found
  1884.         inc     di
  1885.         mov     bx,es:[di]              ;Get offset of ErrorMode flag
  1886.         clc
  1887. findCEF_exit:
  1888.         ret
  1889. findCEF_notfound:
  1890.         stc
  1891.         mov    dx,offset errmsg5    ;Can't find Critical Error flg
  1892.         jmp     short findCEF_exit
  1893. findCEF        endp
  1894.  
  1895. ;-----------------------------------------------------------------------------
  1896. ; FIND INSTALLED Find the installed code by scanning the memory control blocks.
  1897. ; Exit:   AX - Segment of installed code if found.
  1898. ;         CF - Clear if installed code found
  1899. ;-----------------------------------------------------------------------------
  1900. find_installed  proc    near
  1901.             assume  ds:code,es:code
  1902.             mov     word ptr prog,0
  1903.             mov     bx,0A000h               ;Start at upper mem blk start
  1904.             mov     ax,cs                   ;keep CS value in AX
  1905. find_installed_1:
  1906.             inc     bx                      ;increment search segment value
  1907.             mov     es,bx
  1908.             assume  es:nothing
  1909.             cmp     ax,bx                   ;not installed if current
  1910.             je      find_installed_2        ;  segment is found.
  1911.             call    cmpheader
  1912.             jne     find_installed_1        ;loop back if not found
  1913.  
  1914.             clc
  1915. find_installed_exit:
  1916.             ret
  1917. find_installed_2:
  1918.             stc
  1919.             jmp     short find_installed_exit
  1920. find_installed  endp
  1921.  
  1922. ;-----------------------------------------------------------------------------
  1923. ; CMPHEADER compares the first 16 bytes of this file with the segment
  1924. ;           pointed to by ES.
  1925. ; Entry:  DS - code segment
  1926. ;         ES - pointer to segment to compare
  1927. ; Exit:   ZF - 0 = segments match.
  1928. ;-----------------------------------------------------------------------------
  1929. cmpheader       proc    near
  1930.             assume  ds:code,es:nothing
  1931.             mov     si,offset prog          ;Search this segment for ASCII
  1932.             mov     di,si                   ;  fingerprint.
  1933.             mov     cx,16
  1934.             repe    cmpsb
  1935.             ret
  1936. cmpheader       endp
  1937.  
  1938. ;-----------------------------------------------------------------------------
  1939. ; PRINTMSG prints the message pointed to by DX to the screen.
  1940. ; Entry:  DX - pointer to ASCII message terminated by $
  1941. ;-----------------------------------------------------------------------------
  1942. printmsg        proc    near
  1943.             assume  ds:nothing,es:nothing
  1944.             push    ds
  1945.             push    cs
  1946.             pop     ds
  1947.             assume  ds:code
  1948.             mov     ah,9                    ;Print message
  1949.             int     21h
  1950.             pop     ds
  1951.             ret
  1952. printmsg        endp
  1953.  
  1954. ;-----------------------------------------------------------------------------
  1955. ; PRINTMSGCR calls PRINTMSG, then appends a carriage return to the message.
  1956. ; Entry:  DX - pointer to ASCII message terminated by $
  1957. ;-----------------------------------------------------------------------------
  1958. printmsgcr      proc    near
  1959.             assume  ds:nothing,es:nothing
  1960.             push    dx
  1961.             call    printmsg
  1962.             mov     dx,offset endmsg
  1963.             call    printmsg
  1964.             pop     dx
  1965.             ret
  1966. printmsgcr      endp
  1967.             even
  1968. end_of_code     =       $
  1969. code            ends
  1970.  
  1971. end             prog
  1972. 
  1973.